﻿using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Web;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Net;
using System.IO;
using PeoplePickerPlus.Helpers;

namespace PeoplePickerPlus.Layouts.PeoplePickerPlus
{
    public partial class UserImageProxy : System.Web.UI.Page
    {
        private const int DefaultCacheMinutes = 1440;
        private static TimeSpan _UserImageCacheTime = TimeSpan.Zero;
        private const string USER_LIST_FIELDS = "<FieldRef Name='Picture'/>";

        public static TimeSpan UserImageCacheTime
        {
            get
            {
                if (_UserImageCacheTime == TimeSpan.Zero)
                {
                    string cacheSetting = Configuration.GetAppSetting(Configuration.UserImageCacheTimeSetting, DefaultCacheMinutes.ToString());

                    try
                    {
                        _UserImageCacheTime = TimeSpan.FromMinutes(Convert.ToDouble(cacheSetting));
                    }
                    catch (Exception ex)
                    {
                        Logging.LogError(ex);
                        _UserImageCacheTime = TimeSpan.FromMinutes(DefaultCacheMinutes);
                    }
                }
                return _UserImageCacheTime;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            string proxyURL = string.Empty;
            try
            {
                proxyURL = GetProxyUrl();//HttpUtility.UrlDecode(Request.QueryString["u"].ToString());
            }
            catch { }

            if (!string.IsNullOrEmpty(proxyURL))
            {
                SetClientCaching(proxyURL);

                ProxyRequest(proxyURL, true);
            }
        }

        private void SetClientCaching(string url)
        {
            Response.Cache.SetETag(url);
            Response.Cache.SetLastModified(DateTime.Now);
            Response.Cache.SetCacheability(HttpCacheability.Public);
            Response.Cache.SetMaxAge(UserImageCacheTime);
            Response.Cache.SetSlidingExpiration(true);
        }

        private string GetProxyUrl()
        {
            try
            {
                string userID = Request.Params["id"];

                if (!string.IsNullOrEmpty(userID))
                {
                    return GetUserPictureUrl(userID);
                }
            }
            catch
            {
                //just return default
            }
            return DefaultImageUrl;
        }

        private string GetUserPictureUrl(string username)
        {
            string imageUrl = DefaultImageUrl;
            
            SPQuery query = new SPQuery()
            {
                ViewFields = USER_LIST_FIELDS,
                IncludePermissions = false,
                IncludeAllUserPermissions = false,
                IncludeAttachmentUrls = false,
                IncludeAttachmentVersion = false,
                IncludeMandatoryColumns = false,
                RecurrenceOrderBy = false,
                ViewFieldsOnly = true,
                RowLimit = 1,
            };
            query.Query = string.Format("<Where><Eq><FieldRef Name='Name' /><Value Type='Text'>{0}</Value></Eq></Where>", 
                EntityManager.EncodeForCAML(username));
            SPListItemCollection items = SPContext.Current.Web.SiteUserInfoList.GetItems(query);

            if (items.Count > 0)
            {
                SPFieldUrlValue urlValue = new SPFieldUrlValue(items[0]["Picture"] as string);

                if (urlValue != null && !string.IsNullOrEmpty(urlValue.Url))
                {
                    imageUrl = urlValue.Url;
                }
            }

            return imageUrl;
            
            /*get from profile service... but this is 1)expensive 2)not compat with SP Foundation? 3)Breaks if profile svc down
            /*
            SPServiceContext serviceContext = SPServiceContext.GetContext(SPContext.Current.Site);
            UserProfileManager upm = new UserProfileManager(serviceContext);
            if (upm.UserExists(username))
            {
                UserProfile profile = upm.GetUserProfile(username);
                if (profile != null)
                {
                    Url = profile["PictureURL"].Value.ToString();
                }
            }
 
            //change it to the default if the user does not have an image specified
            if (string.IsNullOrEmpty(Url))
                Url = "/_layouts/images/O14_person_placeHolder_96.png";
 
            return Url;
            */
        }

        private string DefaultImageUrl
        {
            get
            {
                return string.Format("{0}/_layouts/images/o14_person_placeholder_32.png", SPContext.Current.Site.Url.TrimEnd('/'));
            }
        }

        [DllImport("advapi32.dll")]
        private static extern int RevertToSelf();

        public void ProxyRequest(string url, bool fallback)
        {
            Exception error = null;
            WindowsIdentity connectedUser = WindowsIdentity.GetCurrent();
            RevertToSelf();

            try
            {
                ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(
                    ValidateRemoteCertificate
                );

                HttpWebRequest ProxyRequest = (
                    HttpWebRequest)WebRequest.Create(url);
                ProxyRequest.ServicePoint.ConnectionLimit = Math.Max(20, ServicePointManager.DefaultConnectionLimit);
                ProxyRequest.ServicePoint.Expect100Continue = false;

                ProxyRequest.Proxy = null;
                ProxyRequest.KeepAlive = false;

                ProxyRequest.Credentials = CredentialCache.DefaultNetworkCredentials;

                ProxyRequest.Method = "GET";

                using (HttpWebResponse ProxyResponse = (HttpWebResponse)ProxyRequest.GetResponse())
                {
                    try
                    {
                        Response.ContentType = ProxyResponse.ContentType;
                        using (Stream StreamResponse = ProxyResponse.GetResponseStream())
                        {
                            try
                            {
                                int ResponseReadBufferSize = 256;
                                byte[] ResponseReadBuffer = new byte[ResponseReadBufferSize];
                                using (MemoryStream MemoryStreamResponse = new MemoryStream())
                                {
                                    try
                                    {
                                        int ResponseCount = StreamResponse.Read(ResponseReadBuffer, 0,
                                            ResponseReadBufferSize);
                                        while (ResponseCount > 0)
                                        {
                                            //Response.BinaryWrite(ResponseReadBuffer);
                                            MemoryStreamResponse.Write(ResponseReadBuffer, 0,
                                                ResponseCount);
                                            ResponseCount = StreamResponse.Read(ResponseReadBuffer, 0,
                                                ResponseReadBufferSize);
                                        }

                                        Response.BinaryWrite(MemoryStreamResponse.ToArray());
                                        //ResponseDataString = Encoding.ASCII.GetString(MemoryStreamResponse.ToArray());
                                    }
                                    finally
                                    {
                                        MemoryStreamResponse.Close();
                                    }
                                }
                            }
                            finally
                            {
                                StreamResponse.Close();
                            }
                        }
                    }
                    finally
                    {
                        ProxyResponse.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                error = ex;
                
                //
            }
            finally
            {
                connectedUser.Impersonate();
            }

            if (error != null)
            {
                if (fallback)
                {
                    ProxyRequest(url, false);
                }
                else
                {
                    throw new ApplicationException("Error accessing " + url + ": " + error.Message, error);
                }
            }
        }

        private static bool ValidateRemoteCertificate(
            object sender,
                X509Certificate certificate,
                X509Chain chain,
                SslPolicyErrors policyErrors
            )
        {
            return true;
        }
    }

}
